# coding: utf-8
from typing import Union, List

from PySide6.QtCore import Qt, Signal
from PySide6.QtGui import QIcon, QColor
from PySide6.QtWidgets import QWidget, QVBoxLayout, QFileDialog, QHBoxLayout, QListWidgetItem, QSizePolicy
from qfluentwidgets import SingleDirectionScrollArea, FluentIcon as FIF, Slider, PrimaryPushButton, LineEdit, BodyLabel, \
    Action, InfoBar, StateToolTip, IconWidget, FluentIconBase, ListWidget, PushButton, setFont, MessageBox, \
    setCustomStyleSheet
from qfluentwidgets.components.material import AcrylicComboBox

from common import BatchTTSThread, VoiceThread, TranslationDict, Files, QFileManager


class ItemWidget(QWidget):
    valueChanged = Signal(int)

    def __init__(self, icon: Union[str, QIcon, FluentIconBase], title: str, content: str, parent=None):
        super().__init__(parent)
        self.horizontalLayout = QHBoxLayout(self)
        self.iconWidget = IconWidget(icon, self)
        self.titleLabel = BodyLabel(title, self)
        self.contentLabel = BodyLabel(content, self)
        self.slider = None

        self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
        self.horizontalLayout.setAlignment(Qt.AlignmentFlag.AlignLeft)
        self.iconWidget.setFixedSize(16, 16)
        self.horizontalLayout.addWidget(self.iconWidget)
        self.horizontalLayout.addWidget(self.titleLabel)
        self.horizontalLayout.addWidget(self.contentLabel)
        self.horizontalLayout.addStretch(1)

        setFont(self.contentLabel, 11)
        self.contentLabel.setTextColor(QColor(0, 0, 0, 100), QColor(255, 255, 255, 100))

    def setContent(self, content: str):
        self.contentLabel.setText(content)

    def addSlider(self):
        self.slider = Slider(Qt.Orientation.Horizontal, self)
        self.slider.valueChanged.connect(self.valueChanged)
        self.slider.setRange(-300, 300)
        self.slider.setValue(0)
        self.addWidget(self.slider)
        return self.slider

    def value(self):
        if self.slider:
            return self.slider.value()
        else:
            return 0

    def addWidget(self, widget: QWidget):
        widget.setMinimumWidth(300)
        widget.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Preferred)
        self.horizontalLayout.addWidget(widget, 1)


class BatchInterface(SingleDirectionScrollArea):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.scrollWidget = QWidget(self)
        self.verticalLayout = QVBoxLayout(self.scrollWidget)
        self.horizontalLayout = QHBoxLayout()
        self.horizontalLayout_2 = QHBoxLayout()
        self.horizontalLayout_3 = QHBoxLayout()
        self.verticalLayout_2 = QVBoxLayout()
        self.files = []  # type: List[str]

        # 语音设置
        self.languageLabel = BodyLabel('语言:', self)
        self.languageComboBox = AcrylicComboBox(self)
        self.voiceLabel = BodyLabel('声音:', self)
        self.voiceComboBox = AcrylicComboBox(self)

        self.rateItemWidget = ItemWidget(FIF.SPEED_MEDIUM, '语速', '--rate=0%', self)
        self.volumeItemWidget = ItemWidget(FIF.VOLUME, '音量', '--volume=0%', self)
        self.pitchItemWidget = ItemWidget(FIF.MARKET, '音调', '--pitch=0%', self)
        self.saveItemWidget = ItemWidget(FIF.SAVE, '保存路径', '--output-file=', self)
        self.saveLineEdit = LineEdit(self)
        self.startItemWidget = ItemWidget(FIF.PLAY, '开始合成', '', self)
        self.startButton = PrimaryPushButton(FIF.PLAY, '开始合成', self)
        self.fileListWidget = ListWidget(self)
        self.addFileButton = PushButton(FIF.ADD, '添加文件', self)
        self.deleteFileButton = PushButton(FIF.DELETE, '删除文件', self)

        self.stateToolTip = StateToolTip('合成中', '正在合成，请稍候...', self)

        self.batchTTSThread = BatchTTSThread(self)
        self.voiceThread = VoiceThread(self)
        self.shortName = None

        self.__initWidgets()
        self.__connectSignals()

        self.__initLanguageComboBox()
        self.setLanguage('zh-CN')

    def __initWidgets(self):
        self.setObjectName('BatchInterface')
        self.scrollWidget.setAutoFillBackground(False)
        self.setWidget(self.scrollWidget)
        self.setWidgetResizable(True)
        self.enableTransparentBackground()

        self.languageLabel.setFixedWidth(50)
        self.languageComboBox.setMaxVisibleItems(10)
        self.voiceComboBox.setMaxVisibleItems(10)
        self.voiceLabel.setFixedWidth(50)
        self.stateToolTip.setVisible(False)

        self.rateItemWidget.addSlider()
        self.volumeItemWidget.addSlider()
        self.pitchItemWidget.addSlider()

        self.saveLineEdit.setPlaceholderText('保存路径')
        self.saveLineEdit.setReadOnly(True)
        self.saveLineEdit.addAction(
            Action(FIF.FOLDER_ADD, '保存路径', self.saveLineEdit, triggered=self.onSaveLineEditActionTriggered))
        self.saveItemWidget.addWidget(self.saveLineEdit)
        self.startItemWidget.addWidget(self.startButton)
        qss = 'ListWidget {border: 1px solid #ccc; border-radius: 5px; padding: 5px;}'
        setCustomStyleSheet(self.fileListWidget, qss, qss)

        self.verticalLayout.setAlignment(Qt.AlignmentFlag.AlignTop)
        self.verticalLayout_2.setAlignment(Qt.AlignmentFlag.AlignTop)
        self.horizontalLayout.setAlignment(Qt.AlignmentFlag.AlignLeft)
        self.horizontalLayout_2.setAlignment(Qt.AlignmentFlag.AlignLeft)
        self.verticalLayout.setContentsMargins(20, 20, 20, 20)

        self.horizontalLayout.addWidget(self.languageLabel)
        self.horizontalLayout.addWidget(self.languageComboBox, 1)
        self.horizontalLayout.addWidget(self.voiceLabel)
        self.horizontalLayout.addWidget(self.voiceComboBox, 1)
        self.verticalLayout.addLayout(self.horizontalLayout)

        self.verticalLayout.addWidget(self.rateItemWidget)
        self.verticalLayout.addWidget(self.volumeItemWidget)
        self.verticalLayout.addWidget(self.pitchItemWidget)
        self.verticalLayout.addWidget(self.saveItemWidget)
        self.verticalLayout.addWidget(self.startItemWidget)

        self.horizontalLayout_3.addWidget(self.fileListWidget)
        self.verticalLayout_2.addWidget(self.addFileButton)
        self.verticalLayout_2.addWidget(self.deleteFileButton)
        self.horizontalLayout_3.addLayout(self.verticalLayout_2)

        self.verticalLayout.addLayout(self.horizontalLayout_2)
        self.verticalLayout.addLayout(self.horizontalLayout_3)

    def __connectSignals(self):
        self.rateItemWidget.valueChanged.connect(lambda value: self.rateItemWidget.setContent(f'--rate={value}%'))
        self.volumeItemWidget.valueChanged.connect(lambda value: self.volumeItemWidget.setContent(f'--volume={value}%'))
        self.pitchItemWidget.valueChanged.connect(lambda value: self.pitchItemWidget.setContent(f'--pitch={value}%'))
        self.addFileButton.clicked.connect(self.onAddFileButtonClicked)
        self.deleteFileButton.clicked.connect(self.onDeleteFileButtonClicked)
        self.startButton.clicked.connect(self.onStartButtonClicked)

        self.languageComboBox.currentIndexChanged.connect(self.onLanguageComboBoxChanged)
        self.voiceThread.voiceChanged.connect(self.onVoiceChanged)
        self.stateToolTip.closedSignal.connect(self.onStateToolTipClosed)

        self.batchTTSThread.started.connect(self.onBatchTTSThreadStarted)
        self.batchTTSThread.finished.connect(self.onBatchTTSThreadFinished)
        self.batchTTSThread.error.connect(lambda error: InfoBar.error('合成失败', error, parent=self))
        self.batchTTSThread.msg.connect(self.stateToolTip.setContent)

    def onSaveLineEditActionTriggered(self):
        directory = QFileDialog.getExistingDirectory(self, '保存路径', '',
                                                     QFileDialog.Option.DontUseCustomDirectoryIcons)
        if directory:
            self.saveItemWidget.setContent(f'--output-file={directory}')
            self.saveLineEdit.setText(directory)

    def onAddFileButtonClicked(self):
        files, _ = QFileDialog.getOpenFileNames(self, '选择文件', '', '文本文件 (*.txt)')
        if files:
            for file_path in files:
                if file_path in self.files:
                    continue
                self.files.append(file_path)
                item = QListWidgetItem(file_path)
                self.fileListWidget.addItem(item)

    def onDeleteFileButtonClicked(self):
        items = self.fileListWidget.selectedItems()
        if items:
            for item in items:
                self.files.remove(item.text())
                self.fileListWidget.takeItem(self.fileListWidget.row(item))
        self.fileListWidget.clearSelection()

    def onStartButtonClicked(self):
        files = self.files
        voice = self.voiceComboBox.currentData()
        rate = self.rateItemWidget.value()
        volume = self.volumeItemWidget.value()
        pitch = self.pitchItemWidget.value()
        save_path = self.saveLineEdit.text()
        if not files:
            InfoBar.warning('待合成文件不能为空', '请选择待合成文件', parent=self)
        elif not save_path:
            InfoBar.warning('保存路径不能为空', '请选择合成文件保存路径', parent=self)

        self.batchTTSThread.setParams(files, voice, rate, volume, pitch, save_path)

    def __initLanguageComboBox(self):
        with QFileManager(Files.EDGE_TTS) as f:
            keyword = f.read_json().keys()
            for k in keyword:
                self.languageComboBox.addItem(TranslationDict.get(k, k), userData=k)

    def onVoiceChanged(self, voices: list):
        self.voiceComboBox.clear()

        for voice in voices:
            FriendlyName = TranslationDict.get(voice.get('FriendlyName', ''), voice.get('FriendlyName', ''))
            ShortName = voice.get('ShortName', '')
            self.voiceComboBox.addItem(FriendlyName, userData=ShortName)
            if self.shortName == ShortName:
                self.voiceComboBox.setCurrentText(FriendlyName)

    def setLanguage(self, language: str, shortName: str = None):
        self.shortName = shortName
        self.languageComboBox.setCurrentText(TranslationDict.get(language, language))
        self.voiceThread.setKey(language)

    def onLanguageComboBoxChanged(self, index: int):
        user_data = self.languageComboBox.itemData(index)
        self.voiceThread.setKey(user_data)

    def onBatchTTSThreadStarted(self):
        self.addFileButton.setEnabled(False)
        self.startButton.setEnabled(False)
        self.deleteFileButton.setEnabled(False)
        self.stateToolTip.setVisible(True)

    def onBatchTTSThreadFinished(self):
        self.addFileButton.setEnabled(True)
        self.startButton.setEnabled(True)
        self.deleteFileButton.setEnabled(True)
        self.stateToolTip.setVisible(False)
        InfoBar.success('合成完成', '合成完成，请到保存路径查看', duration=3000, parent=self)

    def resizeEvent(self, event):
        self.stateToolTip.move(self.width() - self.stateToolTip.width() - 10, 50)
        super().resizeEvent(event)

    def onStateToolTipClosed(self):
        def on_yes():
            self.stateToolTip.setVisible(False)
            self.batchTTSThread.terminate()

        dialog = MessageBox('你确定要退出吗？', '终止合成进程将导致未完成的合成文件丢失，是否确定退出？', self)
        dialog.yesSignal.connect(on_yes)
        dialog.exec()
